<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
  <head> 
    <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type"> 
    <script language="javascript">
      // Split a string in 2 parts. The first is the leading number, if any,
      // the second is the string following the numbers.
      function splitNum(s) {
        var results = new Array();
        results[0] = 'None';
        for (var i = 0; i < s.length; i++) {
          var substr = s.substr(0, i+1)
          if (isNaN(substr)) {
            // Not a number anymore.
            results[1] = s.substr(i)
            break;
          } else {
            // This is a number. update the results.
            results[0] = parseFloat(substr);
          }
        }
        return results;
      }

      // Compare 2 strings using a custom alphanumerical algorithm.
      // This is similar to a normal string sort, except that we sort
      // first by leading digits, if any.
      // For example:
      //  100hello > 2goodbye
      // Numbers anywhere else in the string are compared using the normal
      // sort algorithm.
      function alphanumCompare(a, b) {
        var parsedA = splitNum(a);
        var parsedB = splitNum(b);
        var numA = parsedA[0];
        var numB = parsedB[0];
        var strA = parsedA[1];
        var strB = parsedB[1];

        if (isNaN(numA) == false && isNaN(numB) == false) {
          // They both start with numbers.
          if (numA < numB) return -1;
          if (numA > numB) return 1;
          // Identical. Fallback to string.
          return (strA < strB) ? -1 : (strA > strB ? 1 : 0)
        }

        // If only one starts with a number, we start with that one as
        // the lowest.
        if (isNaN(numA) == false) return -1
        if (isNaN(numB) == false) return 1
       
        // They are both strings. 
        return (a < b) ? -1 : (a > b ? 1 : 0)
      }
    </script>
  </head> 
  <body> 
    <script type="application/javascript"> 
      String.prototype.startsWith = function(str) {
        return (this.match('^' + str) == str)
      }
 
      // Helper function to retrieve the value of a GET query parameter.
      // Greatly inspired from http://alturl.com/8rj7a
      function getParameter(parameterName) {
        // Add '=' to the parameter name (i.e. parameterName=value)
        var parameterName = parameterName + '=';
        var queryString = window.location.search.substring(1);
        if (queryString.length <= 0) {
          return '';
        }
        
        // Find the beginning of the string
        begin = queryString.indexOf(parameterName);
 
        // If the parameter name is not found, skip it, otherwise return the
        // value.
        if (begin == -1) {
          return '';
        }
         
        // Add the length (integer) to the beginning.
        begin += parameterName.length;
 
        // Multiple parameters are separated by the '&' sign.
        end = queryString.indexOf ('&', begin);
        
        if (end == -1) {
          end = queryString.length;
        }
        
        // Return the string.
        return unescape(queryString.substring(begin, end));
      }
 
      // Given a tag and a node, returns the value for this tag on this node.
      function getNodeValue(node, tag) {
        return node.getElementsByTagName(tag)[0].firstChild.nodeValue;
      }

      // Displays the directory listing given the XML and path.
      function displayList(xmlstring, root, path, pathRoot) {
        // Display the header
        document.write('<h1>Index of /' + path + '</h1>');
 
        // Start the table for the results.
        document.write('<table style="border-spacing:15px 0px;">');

        var sortOrder = getParameter('sort');
        var sortLink = location.pathname + '?path=' + path;
        if (sortOrder != 'desc') {
          sortLink += '&sort=desc';
        }
 
        // Display the table header.
        document.write('<tr><th><img src="' + root + pathRoot +
                       'icons/blank.gif" alt="[ICO]"></th>');
        document.write('<th><a href="' + sortLink + '">Name</a></th>');
        document.write('<th>Last modified</th>');
        document.write('<th>Size</th>');
        document.write('<th>Storage Class</th>');
        document.write('<th>ETag</th></tr>');
        document.write('<tr><th colspan="6"><hr></th></tr>');
 
        // Display the 'go back' button.
        if (path != '') {
          var backpath = location.pathname;
 
          // If there is more than one section delimited by '/' in the current
          // path we truncate the last section and append the rest to backpath.
          var delimiter = path.lastIndexOf('/');
          if (delimiter >= 0) {
            delimiter = path.substr(0, delimiter).lastIndexOf('/');
            if (delimiter >= 0) {
              backpath += '?path=';
              backpath += path.substr(0, delimiter+1);
            }
          }
 
          document.write('<tr><td valign="top"><img src="' + root + pathRoot +
                         'icons/back.gif" alt="[DIR]"></td>');
          document.write('<td><a href="');
          document.write(backpath);
          document.write('">Parent Directory</a></td>');
          document.write('<td>&nbsp;</td>');
          document.write('<td align="right">  - </td></tr>'); 
        }
 
        // Set up the variables.
        var directories = new Array();
        var files = new Array();

        for (var iter = 0; iter < xmlstrings.length; iter++) {
          var xmlstring = xmlstrings[iter];
          // Parse the XML output.
          var parser = new DOMParser();
          var xmlDoc = parser.parseFromString(xmlstring, 'text/xml');
 
          // Get the main element.
          var results = xmlDoc.getElementsByTagName('ListBucketResult');
 
          // Get all the directories.
          var prefixes = results[0].getElementsByTagName('CommonPrefixes');
          for (var i = 0; i < prefixes.length; i++) {
            var prefix = getNodeValue(prefixes[i], 'Prefix');
            directories.push(prefix.substr(path.length));
        }
      
          // Get all the files.
          var contents = results[0].getElementsByTagName('Contents');
          for (var i = 0; i < contents.length; i++) {
            var obj = new Object();
            obj.keyName = getNodeValue(contents[i], 'Key');
            obj.lastModified = getNodeValue(contents[i], 'LastModified');
            obj.eTag = getNodeValue(contents[i], 'ETag');
            obj.size = getNodeValue(contents[i], 'Size');
            files.push(obj);
          }
        }
 
        files.sort(alphanumCompare);
        directories.sort(alphanumCompare);

        // Reverse the list for a descending sort.
        if (sortOrder == 'desc') {
          files.reverse();
          directories.reverse();
        }
      
        // Display the directories.
        for (var i = 0; i < directories.length; i++) {
          var lnk = location.pathname.substr(0, location.pathname.indexOf('?'));
          lnk += '?path=' + path + directories[i];
      
          document.write('<tr>');
          document.write('<td valign="top"><img src="' + root + pathRoot +
                         'icons/folder.gif" alt="[DIR]"></td>');
          document.write('<td><a href="' + lnk + '">' +
                         directories[i].split('/')[0] + '</a></td>');
          document.write('<td align="right">-</td>');
          document.write('<td align="right">-</td>');
          document.write('<td align="right">-</td>');
          document.write('<td align="right">-</td>');
          document.write('</tr>');
        }
      
        // Display the files.
        for (var i = 0; i < files.length; i++) {
          var link = root + files[i].keyName;
          var filename = files[i].keyName.substr(path.length);
          var size = files[i].size / 1024 / 1024;
          var lastModified = files[i].lastModified.replace('T', ' ');
          lastModified = lastModified.substr(0, lastModified.indexOf('.'));
          
          // Remove the entries we don't want to show.
          if (filename == '') {
            continue;
          }
        
          if (filename.indexOf('$folder$') >= 0) {
            continue;
          }
        
          // Display the row.
          document.write('<tr>');
          document.write('<td valign="top"><img src="' + root + pathRoot +
                         'icons/binary.gif" alt="[DIR]"></td>');
          document.write('<td><a href="' + link + '">' + filename +
                         '</a></td>');
          document.write('<td align="right">' + lastModified + '</td>');
          document.write('<td align="right">' + size.toFixed(2) + 'MB</td>');
          document.write('<td align="right"><pre>' +
                         files[i].eTag.split('"')[1] + '</pre></td>');
          document.write('</tr>');
        }
 
        // Close the table.
        document.write('<tr><th colspan="6"><hr></th></tr>');
        document.write('</table>');
      }
 
      var xmlstrings = new Array();

      function fetchAndDisplay(marker) {
        var path = getParameter('path');
        var lastSlash = location.pathname.lastIndexOf("/");
        var filename = location.pathname.substring(lastSlash + 1);
        var firstSlash = location.pathname.indexOf("/", 1);
        var root = location.pathname.substring(0, firstSlash + 1);
        var pathRoot = location.pathname.substring(firstSlash + 1,
                                                   lastSlash + 1);
        if (!path) {
          path = location.pathname.substring(firstSlash + 1, lastSlash + 1);
        }

        var markerParam = '';
        if (marker != '') {
          markerParam = '&marker=' + marker;
        }

        var http = new XMLHttpRequest();
        http.open('GET',
                  root + '?delimiter=/&prefix=' + path + markerParam,
                  true);
        http.onreadystatechange = useHttpResponse;
        http.send(null);
        function useHttpResponse() {
          if (http.readyState == 4) {
            var xmlstring = http.responseText;
            xmlstrings.push(xmlstring);
    
            // Check if the data is truncated. if so, we need to request the
            // rest.
            var parser = new DOMParser();
            var xmlDoc = parser.parseFromString(xmlstring, 'text/xml');

            // Get the main element.
            var results = xmlDoc.getElementsByTagName('ListBucketResult');

            // Get IsTruncated.
            var truncated = getNodeValue(results[0], 'IsTruncated');
            var nextMarker = '';
            if (truncated == 'true') {
              nextMarker = getNodeValue(results[0], 'NextMarker');
              fetchAndDisplay(nextMarker);
            } else {
              displayList(xmlstrings, root, path, pathRoot);
            }
          }
        }
      }
      
      fetchAndDisplay('');
    </script> 
  </body> 
</html>
